
package com.hexinfo.dmpro.dev.data.transfer.service.impl;

import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.entity.TemplateExportParams;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hexinfo.dmpro.common.base.PageResult;
import com.hexinfo.dmpro.common.utils.CommonConstants;
import com.hexinfo.dmpro.component.common.service.impl.HiveQueryService;
import com.hexinfo.dmpro.component.common.util.DataSourceUtil;
import com.hexinfo.dmpro.component.file.transfer.service.FileTransferService;
import com.hexinfo.dmpro.data.transfer.common.common.manager.AgentManager;
import com.hexinfo.dmpro.data.transfer.common.common.util.ShellUtil;
import com.hexinfo.dmpro.data.transfer.common.model.CdhFieldEntity;
import com.hexinfo.dmpro.data.transfer.common.model.SourceRuleTableView;
import com.hexinfo.dmpro.data.transfer.common.service.ICdhMetadataService;
import com.hexinfo.dmpro.dev.data.transfer.common.enums.DevDataTransferExportTaskStatusEnum;
import com.hexinfo.dmpro.dev.data.transfer.common.enums.DevDataTransferListStatusEnum;
import com.hexinfo.dmpro.dev.data.transfer.common.enums.DevDataTransferRebuildListExceptionEnum;
import com.hexinfo.dmpro.dev.data.transfer.dao.DevDataExportListMapper;
import com.hexinfo.dmpro.dev.data.transfer.handle.IDevDataExportHandler;
import com.hexinfo.dmpro.dev.data.transfer.model.DesensitizeFieldList;
import com.hexinfo.dmpro.dev.data.transfer.model.DevDataExportList;
import com.hexinfo.dmpro.dev.data.transfer.model.DevDataExportTask;
import com.hexinfo.dmpro.dev.data.transfer.service.IDesensitizeFieldListService;
import com.hexinfo.dmpro.dev.data.transfer.service.IDevDataExportListService;
import com.hexinfo.dmpro.dev.data.transfer.service.IDevDataExportTaskService;
import com.hexinfo.dmpro.dev.data.transfer.utils.ExcelUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.File;
import java.sql.Connection;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 表导出任务集合表
 *
 * @author yyh.huang
 * @date 2023-10-25 19:17:01
 */
@Slf4j
@Service
@RequiredArgsConstructor(onConstructor_ = {@Lazy, @Autowired})
public class DevDataExportListServiceImpl extends ServiceImpl<DevDataExportListMapper, DevDataExportList> implements IDevDataExportListService {

    private final IDevDataExportTaskService devDataExportTaskService;

    private final AgentManager agentManager;

    private final IDevDataExportHandler devDataExportHandler;

    private final IDesensitizeFieldListService desensitizeFieldListService;

    private final HiveQueryService hiveQueryService;

    private final ICdhMetadataService cdhMetadataService;

    private final FileTransferService fileTransferService;

    @Value("${dev-data-export-retry-count}")
    private Integer retryCount;

    @Value("${dev-data-ftp.server}")
    private String ftpServer;

    @Value("${dev-data-ftp.port}")
    private Integer ftpPort;

    @Value("${dev-data-ftp.user}")
    private String ftpUserName;

    @Value("${dev-data-ftp.password}")
    private String ftpPassword;

    @Value("${script.pack.relativePath}")
    private String relativePath;

    @Override
    public PageResult queryList(Page page, DevDataExportList devDataExportList) {
        LambdaQueryWrapper<DevDataExportList> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(DevDataExportList::getDel, CommonConstants.STATUS_NORMAL);
        if (StrUtil.isNotBlank(devDataExportList.getTaskCode())) {
        wrapper.like(DevDataExportList::getTaskCode, devDataExportList.getTaskCode());
        }
        if (StrUtil.isNotBlank(devDataExportList.getDbName())) {
            wrapper.like(DevDataExportList::getDbName, devDataExportList.getDbName());
        }
        if (StrUtil.isNotBlank(devDataExportList.getTableName())) {
            wrapper.like(DevDataExportList::getTableName, devDataExportList.getTableName());
        }
        if (StrUtil.isNotBlank(devDataExportList.getErrorMessage())) {
            wrapper.like(DevDataExportList::getErrorMessage, devDataExportList.getErrorMessage());
        }
        if (StrUtil.isNotBlank(devDataExportList.getExportStatus())) {
            wrapper.eq(DevDataExportList::getExportStatus, devDataExportList.getExportStatus());
        }
        if (CollectionUtil.isNotEmpty(devDataExportList.getCreateTimeRange())) {
            Date beginTime = DateUtil.parse(devDataExportList.getCreateTimeRange().get(0));
            Date endTime = DateUtil.parse(devDataExportList.getCreateTimeRange().get(1));
            wrapper.between(DevDataExportList::getCreateTime, beginTime, endTime);
        }
        wrapper.orderByDesc(DevDataExportList::getCreateTime).orderByAsc(DevDataExportList::getDbName).orderByAsc(DevDataExportList::getTableName);
        Page returnPage = this.baseMapper.selectPage(page, wrapper);
        return new PageResult(returnPage.getRecords(), returnPage.getTotal());
    }

    @Override
    public List<DevDataExportList> queryListByTaskCode(String taskCode) {
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq("task_code", taskCode);
        return this.baseMapper.selectList(queryWrapper);
    }

    /*
     * @Method: updateStatus <br>
     * @Param: [devDataExportList] <br>
     * @Return: void <br>
     * @Description：更新导出清单状态<br>
     * @Author： wz.li<br>
     * @Date： 2023/11/11 18:03 <br>
     * @Version： V2.0.2<br>
     */
    @Override
    public void updateStatus(DevDataExportList devDataExportList) {
        DevDataExportList dbDevDataExportList = getById(devDataExportList.getId());
        if (DevDataTransferListStatusEnum.RUNNING.getValue().equals(dbDevDataExportList.getExportStatus())) {
            agentManager.removeExecuteTask(devDataExportList.getAgentKey());
            removeHdfsTmpDir(devDataExportList.getTaskCode());
            // 执行失败且失败次数小于重试次数自动重试
            if (DevDataTransferListStatusEnum.FAIL.getValue().equals(devDataExportList.getExportStatus())
                    && dbDevDataExportList.getErrorCount() < retryCount) {
                exportRetryHandler(devDataExportList.getId());
            } else {
                exportFinishHandler(devDataExportList);
            }
        }
    }

    @Transactional
    public void exportFinishHandler(DevDataExportList devDataExportList) {
        updateDevDataExportListStatus(devDataExportList);
//        updateDevDataExportTaskStatus(devDataExportList);
        // 任务完成删除HDFS临时目录
        removeHdfsHdfsTmpDirByTask(devDataExportList.getTaskCode());
        // 状态更新后，若任务结束 统计ftp文件大小
        devDataExportTaskService.countFileSize(devDataExportList.getTaskCode());
    }

    private void exportRetryHandler(String id) {
        this.baseMapper.updateByRetry(id);
        devDataExportHandler.executeExportTask(this.baseMapper.selectById(id));
    }

    private void updateDevDataExportListStatus(DevDataExportList devDataExportList) {
        devDataExportList.setEndTime(DateUtil.date());
        this.updateById(devDataExportList);
    }

    private void updateDevDataExportTaskStatus(DevDataExportList devDataExportList) {
        try {
            if (DevDataTransferListStatusEnum.SUCCESS.getValue().equals(devDataExportList.getExportStatus())) {
                devDataExportTaskService.modifySuccessNumByTaskCode(devDataExportList.getTaskCode());
            } else {
                devDataExportTaskService.modifyFailNumByTaskCode(devDataExportList.getTaskCode());
            }
            devDataExportTaskService.modifyStatusByTaskCode(devDataExportList.getTaskCode(), DateUtil.now());
        } catch (Exception e) {
            log.error(StrUtil.format("[开发数据导出]表{}导出结束后更新任务信息异常：{}", devDataExportList.getDbAndTableName(), e.getMessage()), e);
        } finally {
            // 任务完成删除HDFS临时目录
            removeHdfsHdfsTmpDirByTask(devDataExportList.getTaskCode());
            // 状态更新后，若任务结束 统计ftp文件大小
            devDataExportTaskService.countFileSize(devDataExportList.getTaskCode());
        }
    }

    private void removeHdfsHdfsTmpDirByTask(String taskCode) {
        DevDataExportTask devDataExportTask = devDataExportTaskService.queryByTaskCode(taskCode);
        if (StrUtil.equalsIgnoreCase(devDataExportTask.getTaskStatus(), "complete")) {
            executeRemoveHdfsTmpDir(devDataExportTask.getFilePath());
        }
    }

    private void removeHdfsTmpDir(String taskCode) {
        DevDataExportTask devDataExportTask = devDataExportTaskService.queryByTaskCode(taskCode);
        if (devDataExportTask != null && DevDataTransferExportTaskStatusEnum.complete.getValue().equals(devDataExportTask.getTaskStatus())) {
            String hdfsTmpRootPath = "/tmp/dmpro";
            removeHdfsTmpOutputDir(hdfsTmpRootPath, taskCode);
            removeHdfsTmpInputDir(hdfsTmpRootPath, taskCode);
        }
    }

    private void removeHdfsTmpOutputDir(String hdfsTmpRootPath, String taskCode) {
        String hdfsPath = StrUtil.format("{}/export/dev/output/{}", hdfsTmpRootPath, taskCode);
        executeRemoveHdfsTmpDir(hdfsPath);
    }

    private void removeHdfsTmpInputDir(String hdfsTmpRootPath, String taskCode) {
        String hdfsPath = StrUtil.format("{}/export/dev/input/{}", hdfsTmpRootPath, taskCode);
        executeRemoveHdfsTmpDir(hdfsPath);
    }

    private void executeRemoveHdfsTmpDir(String hdfsPath) {
        String[] shell = new String[]{"sudo", "-u", "hdfs", "hadoop", "fs", "-rm", "-r", "-skipTrash", hdfsPath};
        Map result = ShellUtil.exec(shell);
        if (!result.containsKey("INVOKE_STATUS") || !(boolean) result.get("INVOKE_STATUS")) {
            log.warn(StrUtil.format("删除HDFS目录发生异常: {}", result.get("SHELL_ERR_RESULT")));
        }
    }

    @Override
    @Transactional
    public void restart(List<String> ids) {
        List<DevDataExportList> devDataExportLists = queryRestartListByIds(ids);
        for (DevDataExportList devDataExportList : devDataExportLists) {
            devDataExportHandler.executeExportTask(devDataExportList);
        }
    }

    @Override
    public void restart(String id) {
        DevDataExportList devDataExportList = this.baseMapper.selectById(id);
        devDataExportHandler.executeExportTask(devDataExportList);
    }

    @Override
    public int updateByRestart(String id) {
        return this.baseMapper.updateByRestart(id);
    }

    private List<DevDataExportList> queryRestartListByIds(List<String> ids) {
        List<DevDataExportList> devDataExportLists = new ArrayList<>();
        for (String id : ids) {
            DevDataExportList devDataExportList = this.getById(id);
            if (StrUtil.equalsAny(devDataExportList.getExportStatus(), DevDataTransferListStatusEnum.FAIL.getValue(), DevDataTransferListStatusEnum.SUCCESS.getValue())) {
                resetDevDataExportList(devDataExportList);
                devDataExportLists.add(this.getById(id));
            }
        }
        return devDataExportLists;
    }

    private void resetDevDataExportList(DevDataExportList devDataExportList) {
        this.updateByRestart(devDataExportList.getId());
        if (DevDataTransferListStatusEnum.SUCCESS.getValue().equals(devDataExportList.getExportStatus())) {
            devDataExportTaskService.reduceSuccessNumByTaskCode(devDataExportList.getTaskCode());
        } else if (DevDataTransferListStatusEnum.FAIL.getValue().equals(devDataExportList.getExportStatus())) {
            devDataExportTaskService.reduceFailNumByTaskCode(devDataExportList.getTaskCode());
        }
        devDataExportTaskService.modifyStatusByTaskCode(devDataExportList.getTaskCode(), DateUtil.now());
    }

    @Async("devDataBuildListAsyncTaskExecutor")
    public void buildExportTaskList(DevDataExportTask devDataExportTask, SourceRuleTableView sourceRuleTableView) {
        log.info("构建导出任务清单[{}]开始，开始时间:{}", sourceRuleTableView.getDbNameAndTableName(), DateUtil.now());
        // ① 构建开发数据导出清单基本信息对象
        DevDataExportList devDataExportList = buildDevDataExportListBasic(devDataExportTask, sourceRuleTableView);
        try {
            // ② 构建开发数据同步相关SQL信息
            buildDevDataExportListRelatedSql(devDataExportList, devDataExportTask.getDateList(), sourceRuleTableView);
            // ③ 保存开发数据同步导出清单信息
            this.save(devDataExportList);
            // ④ 执行开发数据同步导出任务
            devDataExportHandler.executeExportTask(devDataExportList);
        } catch (Exception e) {
            log.error(StrUtil.format("构建开发数据导出任务[{}]失败: {}", devDataExportTask.getTaskCode(), e.getMessage()), e);
            exceptionHandler(devDataExportList, e.getMessage());
        } finally {
            log.info("构建导出任务清单[{}]结束，结束时间:{}", sourceRuleTableView.getDbNameAndTableName(), DateUtil.now());
        }
    }


    private void exceptionHandler(DevDataExportList devDataExportList, String errorMessage) {
        saveExportListForFail(devDataExportList, errorMessage);
        updateDevDataExportTaskStatus(devDataExportList);
    }

    private void saveExportListForFail(DevDataExportList devDataExportList, String errorMessage) {
        if (DevDataTransferRebuildListExceptionEnum.not_supported_table.getValue().equals(errorMessage)) {
            devDataExportList.setExportStatus(DevDataTransferListStatusEnum.NOT_SUPPORTED.getValue());
        } else {
            devDataExportList.setExportStatus(DevDataTransferListStatusEnum.BUILD_FAIL.getValue());
        }
        devDataExportList.setStartTime(DateUtil.date());
        devDataExportList.setEndTime(DateUtil.date());
        devDataExportList.setErrorMessage(errorMessage);
        this.save(devDataExportList);
    }

    /*
     * @Method: buildDevDataExportListRelatedSql <br>
     * @Param: [devDataExportList, dateList, sourceRuleTableView] <br>
     * @Return: void <br>
     * @Description：构建导出任务清单相关SQL<br>
     * @Author： wz.li<br>
     * @Date： 2023/11/26 15:51 <br>
     * @Version： V2.0.2<br>
     */
    private void buildDevDataExportListRelatedSql(DevDataExportList devDataExportList, List<String> dateList, SourceRuleTableView sourceRuleTableView) {
        List<CdhFieldEntity> partitionList = cdhMetadataService.queryPartitionList(sourceRuleTableView.getTblDatabaseName(), sourceRuleTableView.getTblName());
        List<CdhFieldEntity> tableFieldList = getTableFieldList(sourceRuleTableView, partitionList);
        devDataExportList.setCreateTableSql(getCreateTableSql(sourceRuleTableView, 0));
        devDataExportList.setHiveQuerySql(getHiveQuerySql(dateList, sourceRuleTableView, tableFieldList));
        devDataExportList.setCreateTxtTableSql(buildCreateTxtTableSql(sourceRuleTableView, tableFieldList));
        devDataExportList.setInsertDataSql(buildInsertDataSql(sourceRuleTableView, tableFieldList, partitionList));
    }

    /*
     * @Method: getTableFieldList <br>
     * @Param: [sourceRuleTableView, partitionList] <br>
     * @Return: java.util.List<com.hexinfo.dmpro.data.transfer.common.model.CdhFieldEntity> <br>
     * @Description：获取指定表所有字段（包括分区字段）<br>
     * @Author： wz.li<br>
     * @Date： 2023/11/26 16:07 <br>
     * @Version： V2.0.2<br>
     */
    private List<CdhFieldEntity> getTableFieldList(SourceRuleTableView sourceRuleTableView, List<CdhFieldEntity> partitionList) {
        List<CdhFieldEntity> tableFieldList = cdhMetadataService.queryColumnList(sourceRuleTableView.getTblDatabaseName(), sourceRuleTableView.getTblName());
        if (CollectionUtil.isEmpty(tableFieldList)) {
            throw new RuntimeException(DevDataTransferRebuildListExceptionEnum.table_column_empty.getValue());
        }
        tableFieldList.addAll(partitionList);
        return tableFieldList;
    }

    /*
     * @Method: getCreateTableSql <br>
     * @Param: [connection, sourceRuleTableView] <br>
     * @Return: java.lang.String <br>
     * @Description：构建目标表建表SQL<br>
     * @Author： wz.li<br>
     * @Date： 2023/11/16 14:40 <br>
     * @Version： V2.0.2<br>
     */
    private String getCreateTableSql(SourceRuleTableView sourceRuleTableView, Integer queryCount) {
        Connection connection = null;
        try {
            connection = DataSourceUtil.getHiveTargetConnection();
            String createTableSql = hiveQueryService.getCreateTableSql(connection, sourceRuleTableView.getTblDatabaseName(), sourceRuleTableView.getTblName());
            if (createTableSql.trim().startsWith("CREATE TABLE")) {
                return createTableSql.replace("CREATE TABLE", "CREATE TABLE IF NOT EXISTS");
            } else if (createTableSql.trim().startsWith("CREATE EXTERNAL TABLE")) {
                return createTableSql.replace("CREATE EXTERNAL TABLE", "CREATE EXTERNAL TABLE IF NOT EXISTS");
            } else {
                throw new RuntimeException(DevDataTransferRebuildListExceptionEnum.not_supported_table.getValue());
            }
        } catch (Exception e) {
            return getCreateTableSqlErrorHandler(sourceRuleTableView, queryCount, e);
        } finally {
            DataSourceUtil.close(connection);
        }
    }

    /*
     * @Method: getCreateTableSqlErrorHandler <br>
     * @Param: [sourceRuleTableView, queryCount, e] <br>
     * @Return: java.lang.String <br>
     * @Description：开发数据导出获取建表语句异常，支持重试3次，中间间隔10s<br>
     * @Author： wz.li<br>
     * @Date： 2023/11/29 17:53 <br>
     * @Version： V2.0.2<br>
     */
    private String getCreateTableSqlErrorHandler(SourceRuleTableView sourceRuleTableView, Integer queryCount, Exception e) {
        if (DevDataTransferRebuildListExceptionEnum.not_supported_table.getValue().equals(e.getMessage())) {
            throw new RuntimeException(e.getMessage(), e);
        } else if (queryCount > 2) {
            String errorMessage = DevDataTransferRebuildListExceptionEnum.get_create_sql_exception.getValue();
            throw new RuntimeException(errorMessage + e.getMessage(), e);
        } else {
            ThreadUtil.sleep(10000);
            return getCreateTableSql(sourceRuleTableView, queryCount + 1);
        }
    }

    /*
     * @Method: buildCreateTxtTableSql <br>
     * @Param: [sourceRuleTableView, tableFieldList] <br>
     * @Return: java.lang.String <br>
     * @Description：构建创建TXT文本表SQL<br>
     * @Author： wz.li<br>
     * @Date： 2023/11/7 18:11 <br>
     * @Version： V2.0.2<br>
     */
    private String buildCreateTxtTableSql(SourceRuleTableView sourceRuleTableView, List<CdhFieldEntity> tableFieldList) {
        List<String> fieldNameList = new ArrayList<>();
        for (CdhFieldEntity cdhFieldEntity : tableFieldList) {
            fieldNameList.add(StrUtil.format("`{}` string", cdhFieldEntity.getFieldName()));
        }
        String tmplate = "CREATE TABLE IF NOT EXISTS {} ({}) ROW FORMAT DELIMITED FIELDS TERMINATED BY '\\001' STORED AS TEXTFILE;";
        return StrUtil.format(tmplate, sourceRuleTableView.getDbNameAndTxtTableName(), StrUtil.join(", ", fieldNameList));
    }

    /*
     * @Method: buildInsertDataSql <br>
     * @Param: [sourceRuleTableView, tableFieldList, partitionList] <br>
     * @Return: java.lang.String <br>
     * @Description：构建插入数据SQL<br>
     * @Author： wz.li<br>
     * @Date： 2023/11/7 18:35 <br>
     * @Version： V2.0.2<br>
     */
    private String buildInsertDataSql(SourceRuleTableView sourceRuleTableView, List<CdhFieldEntity> tableFieldList, List<CdhFieldEntity> partitionList) {
        String partition = "";
        if (CollectionUtil.isNotEmpty(partitionList)) {
            List<String> partitionNameList = partitionList.stream().map(CdhFieldEntity::getFieldName).collect(Collectors.toList());
            partition = StrUtil.format("PARTITION ({})", StrUtil.join(", ", partitionNameList));
        }
        String fieldNames = StrUtil.join(", ", tableFieldList.stream().map(CdhFieldEntity::getHiveQueryFieldName).collect(Collectors.toList()));
        String tmplate = "INSERT OVERWRITE TABLE {} {} SELECT {} FROM {};";
        return StrUtil.format(tmplate, sourceRuleTableView.getDbNameAndTableName(), partition, fieldNames, sourceRuleTableView.getDbNameAndTxtTableName());
    }

    /*
     * @Method: getHiveQuerySql <br>
     * @Param: [devDataExportTask, sourceRuleTableView, tableFieldList] <br>
     * @Return: java.lang.String <br>
     * @Description：获取HIVE查询SQL<br>
     * @Author： wz.li<br>
     * @Date： 2023/11/7 17:53 <br>
     * @Version： V2.0.2<br>
     */
    private String getHiveQuerySql(List<String> dateList, SourceRuleTableView sourceRuleTableView, List<CdhFieldEntity> tableFieldList) {
        String tmplate = "SELECT {} FROM {} WHERE 1 = 1 ";
        String hiveQuerySql = StrUtil.format(tmplate, getSelectField(sourceRuleTableView, tableFieldList), sourceRuleTableView.getDbNameAndTableName());
        hiveQuerySql += addDatePartitionField(dateList, sourceRuleTableView);
        hiveQuerySql += addCustomWhere(sourceRuleTableView.getCustomWhere());
        return hiveQuerySql;
    }

    /*
     * @Method: addCustomWhere <br>
     * @Param: [sourceRuleTableView] <br>
     * @Return: java.lang.String <br>
     * @Description：新增自定义查询条件<br>
     * @Author： wz.li<br>
     * @Date： 2023/12/2 15:55 <br>
     * @Version： V2.0.2<br>
     */
    private String addCustomWhere(String customWhere) {
        if (StrUtil.isNotBlank(customWhere)) {
            String customWhereSql = StrUtil.startWith(customWhere.trim(), "WHERE", true) ? customWhere.trim().substring(5) : customWhere.trim();
            return " AND " + customWhereSql;
        }
        return "";
    }

    /*
     * @Method: addDatePartitionField <br>
     * @Param: [dateList, sourceRuleTableView] <br>
     * @Return: java.lang.String <br>
     * @Description：添加日期分区字段查询条件<br>
     * @Author： wz.li<br>
     * @Date： 2023/11/16 13:54 <br>
     * @Version： V2.0.2<br>
     */
    private String addDatePartitionField(List<String> dateList, SourceRuleTableView sourceRuleTableView) {
        if (StrUtil.isBlank(sourceRuleTableView.getCustomWhere()) && StrUtil.isNotEmpty(sourceRuleTableView.getDatePartitionName())) {
            String startDate = formatDateNew(dateList.get(0), sourceRuleTableView.getDatePartitionFormat());
            String endDate = formatDateNew(dateList.get(1), sourceRuleTableView.getDatePartitionFormat());
            return StrUtil.format(" AND CAST({} AS STRING) BETWEEN '{}' AND '{}'", sourceRuleTableView.getDatePartitionName(), startDate, endDate);
        }
        return "";
    }

    /*
     * @Method: formatDate <br>
     * @Param: [dateStr, length] <br>
     * @Return: java.lang.String <br>
     * @Description：日期分区字段数据格式化<br>
     * @Author： wz.li<br>
     * @Date： 2023/11/16 13:54 <br>
     * @Version： V2.0.2<br>
     */
    private String formatDate(String dateStr, int length) {
        String format = "yyyyMMdd";
        return DateUtil.format(DateUtil.parseDate(dateStr), StrUtil.sub(format, 0, length));
    }

    private String formatDateNew(String dateStr, String format) {
        return DateUtil.format(DateUtil.parseDate(dateStr), format);
    }

    /*
     * @Method: getSelectField <br>
     * @Param: [sourceRuleTableView, tableFieldList] <br>
     * @Return: java.lang.String <br>
     * @Description：获取查询字段-替换脱敏字段<br>
     * @Author： wz.li<br>
     * @Date： 2023/11/7 17:53 <br>
     * @Version： V2.0.2<br>
     */
    private String getSelectField(SourceRuleTableView sourceRuleTableView, List<CdhFieldEntity> tableFieldList) {
        List<DesensitizeFieldList> desensitizeFieldLists = desensitizeFieldListService.queryDesensitizeField(sourceRuleTableView.getTblDatabaseName(), sourceRuleTableView.getTblName());
        if (CollectionUtil.isEmpty(desensitizeFieldLists)) {
            return "*";
        }
        Map<String, DesensitizeFieldList> desensitizeFieldListMap = desensitizeFieldLists.stream().collect(Collectors.toMap(DesensitizeFieldList::getFieldName, desensitizeField -> desensitizeField));
        List<String> fieldNameList = new ArrayList<>();
        for (CdhFieldEntity cdhFieldEntity : tableFieldList) {
            if (desensitizeFieldListMap.containsKey(cdhFieldEntity.getFieldName())) {
                fieldNameList.add(desensitizeFieldListMap.get(cdhFieldEntity.getFieldName()).getDesensitizeFunction());
            } else {
                fieldNameList.add(cdhFieldEntity.getHiveQueryFieldName());
            }
        }
        return StrUtil.join(", ", fieldNameList);
    }

    /*
     * @Method: buildDevDataExportListBasic <br>
     * @Param: [devDataExportTask, sourceRuleTableView] <br>
     * @Return: com.hexinfo.dmpro.dev.data.transfer.model.DevDataExportList <br>
     * @Description：构建导出任务清单基本信息<br>
     * @Author： wz.li<br>
     * @Date： 2023/11/26 15:49 <br>
     * @Version： V2.0.2<br>
     */
    private DevDataExportList buildDevDataExportListBasic(DevDataExportTask devDataExportTask, SourceRuleTableView sourceRuleTableView) {
        DevDataExportList devDataExportList = new DevDataExportList();
        devDataExportList.setTaskCode(devDataExportTask.getTaskCode());
        devDataExportList.setDbName(sourceRuleTableView.getTblDatabaseName());
        devDataExportList.setTableName(sourceRuleTableView.getTblName());
        devDataExportList.setFilePath(devDataExportTask.getFilePath());
        devDataExportList.setIsFileCompress("Y");
        devDataExportList.setIsFtpTransfer("Y");
        devDataExportList.setIsCreateFlagFile("N");
        devDataExportList.setErrorCount(0);
        devDataExportList.setExportStatus(DevDataTransferListStatusEnum.TODO.getValue());
        devDataExportList.setTaskName(devDataExportTask.getTaskName());
        devDataExportList.setExportModel(devDataExportTask.getExportModel());
        devDataExportList.setExportType(devDataExportTask.getExportType());
        devDataExportList.setExportTimeInterval(devDataExportTask.getExportTimeInterval());
        return devDataExportList;
    }

    /**
     * @return String
     * @Method download
     * @Description 开发数据导出表清单下载
     * @Author gxd
     * @Date 2024/1/4 11:57
     **/
    @Override
    public String download(DevDataExportList devDataExportList) {
        String savePath = "";
        try {
            List<DevDataExportList> queryLists = query(devDataExportList);
            String exportPath = relativePath + "/export/";
            savePath = downTabliListFile(exportPath, queryLists);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return savePath;
    }

    /**
     * @Method removeByTaskCode
     * @Param
     * @param taskCode
     * @Return void
     * @Description 根据TaskCode删除
     * @Author Wang zhihao
     * @Date 2024/1/11 18:10
     * @Version V1.0
     */
    @Override
    public void removeByTaskCode(String taskCode) {
        LambdaQueryWrapper<DevDataExportList> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(DevDataExportList::getTaskCode, taskCode);
        remove(wrapper);
    }

    /**
     * @Method logicRemoveByTaskCode
     * @Param
     * @param taskCode
     * @Return void
     * @Description (逻辑删)根据TaskCode删除
     * @Author Wang zhihao
     * @Date 2024/1/15 11:14
     * @Version V1.0
     */
    @Override
    public void logicRemoveByTaskCode(String taskCode) {
        LambdaUpdateWrapper<DevDataExportList> wrapper = Wrappers.lambdaUpdate();
        if (StrUtil.isNotBlank(taskCode)) {
            wrapper.in(DevDataExportList::getTaskCode, taskCode);
        }
        DevDataExportList devDataExportList = new DevDataExportList();
        devDataExportList.setDel("1");
        update(devDataExportList, wrapper);
    }

    /**
     * @Method abolishByTaskCode
     * @Param
     * @param taskCode
     * @Return void
     * @Description 根据TaskCode中止任务list
     * @Author Wang zhihao
     * @Date 2024/1/19 11:22
     * @Version V1.0
     */
    @Override
    public void abolishByTaskCode(String taskCode) {
        LambdaUpdateWrapper<DevDataExportList> wrapper = Wrappers.lambdaUpdate();
        if (StrUtil.isNotBlank(taskCode)) {
            wrapper.in(DevDataExportList::getTaskCode, taskCode);
            wrapper.in(DevDataExportList::getExportStatus, DevDataTransferListStatusEnum.TODO.getValue(), DevDataTransferListStatusEnum.RUNNING.getValue());
        }
        DevDataExportList devDataExportList = new DevDataExportList();
        devDataExportList.setExportStatus(DevDataTransferListStatusEnum.ABOLISH.getValue());
        update(devDataExportList, wrapper);
    }

    /**
     * @return List<DevDataExportList>
     * @Method query
     * @Description 条件查询
     * @Author gxd
     * @param[1] devDataExportList
     * @Date 2024/1/4 14:19
     **/
    private List<DevDataExportList> query(DevDataExportList devDataExportList) {
        LambdaQueryWrapper<DevDataExportList> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(DevDataExportList::getDel, CommonConstants.STATUS_NORMAL);
        if (StrUtil.isNotBlank(devDataExportList.getTaskCode())) {
            wrapper.eq(DevDataExportList::getTaskCode, devDataExportList.getTaskCode());
        }
        if (StrUtil.isNotBlank(devDataExportList.getDbName())) {
            wrapper.like(DevDataExportList::getDbName, devDataExportList.getDbName());
        }
        if (StrUtil.isNotBlank(devDataExportList.getTableName())) {
            wrapper.like(DevDataExportList::getTableName, devDataExportList.getTableName());
        }
        if (StrUtil.isNotBlank(devDataExportList.getErrorMessage())) {
            wrapper.like(DevDataExportList::getErrorMessage, devDataExportList.getErrorMessage());
        }
        if (StrUtil.isNotBlank(devDataExportList.getExportStatus())) {
            wrapper.eq(DevDataExportList::getExportStatus, devDataExportList.getExportStatus());
        }
        wrapper.orderByAsc(DevDataExportList::getDbName).orderByAsc(DevDataExportList::getTableName);
        return this.baseMapper.selectList(wrapper);
    }

    /**
     * @return String
     * @Method
     * @Description 生成本地excel文件
     * @Author gxd
     * @param[1] exportPath
     * @param[2] devDataExportLists
     * @Date 2024/1/5 8:18
     **/
    private String downTabliListFile(String exportPath, List<DevDataExportList> devDataExportLists) {
        Workbook workbook = null;
        File saveFile = null;
        String savePath = "";
        try {
            // 模板位置
            String templateFilePath = "static/export_result_template.xls";
            // 读取模板
            final TemplateExportParams templateExportParams = new TemplateExportParams(templateFilePath);
            // 获取导出数据
            Map<String, Object> sheetMap = new HashMap<>();
            sheetMap.put("devDataExportLists", devDataExportLists.stream().map(t -> JSON.parseObject(JSON.toJSONString(t), Map.class)).collect(Collectors.toList()));

            // 生成数据
            workbook = ExcelExportUtil.exportExcel(templateExportParams, sheetMap);
            // 创建文件
            savePath = exportPath + DateUtil.format(new DateTime(), "yyyyMMddHHmmss") + "_开发数据导出表清单.xls";
            saveFile = ExcelUtils.createDatafile(exportPath, savePath);
            // 写入数据
            ExcelUtils.writeDownloadFileData(saveFile, workbook);
        } catch (Exception e) {
            log.error("导出清单到服务器异常" + e.getMessage(), e);
            throw new RuntimeException("导出清单到服务器异常" + e.getMessage(), e);
        } finally {
            try {
                workbook.close();
            } catch (Exception e) {
                log.error("导出清单时关闭异常");
                e.printStackTrace();
            }
        }
        return savePath;
    }

}
